import { useRef } from "react";
import Taro from "@tarojs/taro";
import { useSetState, useUpdateEffect } from "ahooks";
import Schema, { Rules } from "async-validator";

import useFetch, { UseFetchOptions, UseFetchUrl } from "./useFetch";

type TUseFormOptions<TModel> = UseFetchOptions<any, []> & {
  method?: "POST" | "PUT";
  defaultModel?: Partial<TModel>;
  rules?: Rules;
  /**
   * 更新model后，自动提交，有的场景需要
   */
  submitOnUpdate?: boolean;
};

const useForm = <TModel = Record<string, any>>(
  url: UseFetchUrl<TModel>,
  {
    method,
    submitOnUpdate = false,
    defaultModel = {} as Partial<TModel>,
    rules,
    ...restOptions
  }: TUseFormOptions<TModel> = {}
) => {
  const [model, setModel] = useSetState<TModel & typeof defaultModel>(
    (defaultModel || {}) as TModel
  );

  // @ts-expect-error
  const { run, ...rest } = useFetch(url, method || "POST", {
    ...restOptions,
    manual: true,
  });

  const schemaRef = useRef<any>();

  const runValidate = (data) => {
    return new Promise((resolve, reject) => {
      if (!rules) return resolve(data);

      if (!schemaRef.current) {
        schemaRef.current = new Schema(rules);
      }

      return schemaRef.current.validate(data, (error) => {
        if (error) {
          Taro.showToast({
            icon: "none",
            title: error[0]["message"] || "",
          });

          reject(error);
        } else {
          resolve(data);
        }
      });
    });
  };

  const submit = async (newModel?: any) => {
    const data = { ...model, ...newModel };
    await runValidate(data);
    run(data);
  };

  const submitAsync = async (newModel?: any) => {
    const data = { ...model, ...newModel };
    await runValidate(data);
    const res = await rest.runAsync(data);
    return res;
  };

  useUpdateEffect(
    () => {
      submit();
    },
    submitOnUpdate ? [model] : []
  );

  return {
    ...rest,
    model,
    setModel,

    submit,
    submitAsync,
  };
};

export default useForm;
